<!DOCTYPE html>
<html>
  <head>
    <meta charset="UTF-8" />
    <style>
      body {
        margin: 0;
        font-size: 14px;
      }
    </style>
  </head>

  <body>
    <div id="jsContainer">
      <ul class="js-test" id="jsParent">
        <li data-index="0">1</li>
        <li data-index="1">2</li>
      </ul>
      <span style="font-weight: bold">3</span>
      4
    </div>
    <script type="text/javascript">
        /**
         * 有点像前面一道题的反向操作，这里我们只需要递归赋值即可，
         * 老样子，我们的递归不用返回值的形式传值，传地址直接修改引用的内容不就行了，相当于深搜 ，
         * 这题如果都是普通节点肯定是简简单单，但实际上确实是有个判断，可能为text的形式，
         * 随着而来的问题就是空字符串的存在也需要考虑并排除，
         * getDomMess的第一个判断可能让一些小友摸不着头脑，其实是这样的，因为我们遍历子代时是传了一个空数组的引用过来，
         * 添加对象之前自然是需要先建一个空对象再对其改变，
         * 之所以要判断呢，是因为第一次传入的是一个空对象，也就是说区分一下祖先节点和后面遍历的子节点
         */
      console.log(dom2json());
      function dom2json() {
        let FatherDOM = document.getElementById("jsContainer");
        let returnJson = {};

        //开始获取节点信息
        getDomMess(FatherDOM, returnJson);
        function getDomMess(curDom, curJson) {
          if (curDom != FatherDOM) {
            let emptyObj = {};
            //在原对象里创建新对象推入对象中并将引用其地址
            curJson.push(emptyObj);
            curJson = curJson[curJson.length - 1];
          }

          if (curDom.nodeType == 3) {
            //文本节点
            curJson.tag = "text";
            curJson.content = curDom.nodeValue.trim();
            return;
          } else {
            //普通节点
            let needvalues = ["children", "attributes"];

            //创建必要对象children和attributes
            needvalues.forEach((value) => {
              if (value == "children") {
                curJson[value] = [];
              } else {
                curJson[value] = {};
              }
            });

            //转小写并赋值tag对象
            curJson.tag = curDom.tagName.toLowerCase();

            //在attributes加入节点属性
            for (let i = 0; i < curDom.attributes.length; i++) {
              let curAttr = curDom.attributes[i];
              curJson[needvalues[1]][curAttr.name] = curAttr.value;
            }
          }

          //如果有子节点则递归
          if (curDom.childNodes.length) {
            for (let i = 0; i < curDom.childNodes.length; i++) {
              let curChildNode = curDom.childNodes[i];
              //去掉空白节点：开始确实没注意还能有空白的text节点🤣🤣🤣
              if (
                !(
                  curChildNode.nodeType == 3 &&
                  curChildNode.nodeValue.trim() == ""
                )
              ) {
                getDomMess(curDom.childNodes[i], curJson.children);
              }
            }
          }
        }
        return returnJson;
      }
    </script>
  </body>
</html>
